// in server1.js var http = require("http"); // reference: Node.js HTTP Module var server = http.createServer((request, response) => { response.writeHead(200, {"Content-Type": "text/plain"}); response.write("<h1>Hello World!</h1>"); response.end(); }); server.listen(8080); // Use your port number instead of 8080.How to run?
$ node server1.js
in the command-line interfacehttp://cs.tru.ca:8080
or http://198.162.21.132:8080
on a web browser, not https.
What do you see? Big 'Hello Wrold!'?
require()
do?.listen()
do?.createServer()
?request
and response
, are passed.
request
holds all the information related to the HTTP request sent from a client, and
response
is used to send data back to the client.request
, Node.js IncomingMessage Object
For more information about response
, Node.js HTTP ServerResponse Object
exports
server2.js
into a module?// server2.js var PORT_NO = 8080; // Use your port number, not 8080 var http = require('http'); function start() { var server = http.createServer( (request, response) => { // request: from the client; response: to the client response.writeHead(200, {"Content-Type": "text/plain"}); response.write("<h1>Hello World!</h1>"); response.end(); } ); server.listen(PORT_NO); } // Something more exports.start = start;
index2.js
?// index.2.js var server = require('./server2'); // server2.js; the variable server represents all the exported functions in server2.js server.start(); // .start() is the function that is defined in server2.js and exported.
$ node ./index2
request
and response
to Router?router3.js
function route(request, response) { response.writeHead(200, {'Content-Type': 'text/plain'}); // Plain text, not html text, will be sent back to the client response.write("<h1>Hello World!</h1>"); response.end(); } exports.route = route;
index3.js
, and pass it to the server.index3.js
var server = require('./server3'); var router = require('./router3'); server.start(router);
server3.js
var PORT_NO = 8080; // Use your port number, not 8080 var http = require('http'); function start(router) { // Do we have to require 'router'? var server = http.createServer( (request, response) => { // request: from the client; response: to the client router.route(request, response); } ); server.listen(PORT_NO); } // Something more exports.start = start;
var server = require('./server'); var router = require('./router'); server.start(router);
var PORT_NO = 8080; // Use your port number var http = require('http'); function start(router) { var server = http.createServer( (request, response) => { // request: from the client; response: to the client router.route(request, response); } ); server.listen(PORT_NO); } // Something more exports.start = start;
function route(request, response) { response.writeHead(200, {'Content-Type': 'text/plain'}); // Plain text, not html text, will be sent back to the client response.write("<h1>Hello World!</h1>"); response.end(); } exports.route = route;
request
?
(Note that pathname obtained from url.parse(request.url).pathname
starts with '/'.)
var url = require("url"); // reference: Node.js URL Module function route(request, response) { var pathname = decodeURI(url.parse(request.url).pathname); // decodeURI(): a JS built-in function // reference: JavaScript decodeURI() response.writeHead(200, {"Content-Type": "text/html"}); // text/html, not text/plain, in this example response.write("<h1>Hello World!</h1><br>"); response.write(pathname + "<br>"); response.end(); } exports.route = route;
"tilde-expansion"
module.
After you install the module as $ npm install tilde-expansion
in the current working directory,
var tilde = require("tilde-expansion"); // reference: tilde-expansion tilde(username, function(expanded) { // E.g., "~tom" -> "/home/students/tom" console.log(expanded); });
request.url
.request.url
..sjs
files.
.sjs
files..sjs
files..sjs
files:
proceed()
should be exported.
This function is the starting point in a server-side JS program, like main()
in Java.
// In each .sjs file, // _GET: object for the GET data // _POST: object for the POST data // callback: callback function to pass a message back to the client const proceed = function(_GET, _POST, callback) { ... } exports.proceed = proceed;
proceed()
, the callback function should be used to send any message back to the client.
.proceed()
will be invoked to execuse them.
The return message from .proceed()
will be sent back to the client.
proceed()
,
in which the application code is fully responsible how to use request.url
and how to send messages or data back to the client.
const proceed = function(request, response) { ... } exports.proceed = proceed;
request.url
?var url = require('url'); // reference: Node.js URL Module function route(request, response) { var pathname = decodeURI(url.parse(request.url).pathname); // encodeURI(), decodeURI() // What does decodeURI() do? ... }
$ npm install tilde-expansion
var tilde = require('tilde-expansion'); // reference: tilde-expansion var words = pathname.split('/'); // words[0] is '' and words[1] is '~...' because pathname starts with '/'. E.g, /~tom/... if (words[1] != undefined && words[???][???] == '~') // e.g., pathname is /~tom/... tilde(words[1], function(expanded) { var new_pathname = expanded + '/???'; // 'public_html' should be included. for (var i = 2; i < words.length; i++) new_pathname += '/' + ???; }); else var new_pathname = "/var/www/html" + pathname;
var url = require('url'); function route(request, response) { var pathname = decodeURI(url.parse(request.url).pathname); var tilde = require('tilde-expansion'); var words = pathname.split('/'); // words[0] is '' and words[1] is '~...' because pathname starts with '/'. // Case 1 if (words[???] != undefined && words[???][???] == '~') { // e.g., /~tom/... => '', '~tom', ... tilde(words[1], function(expanded) { // Note that a callback function is used. var new_pathname = expanded + '/???'; // 'public_html' should be included. for (var i = 2; i < words.length; i++) new_pathname += '/' + ???; ???? }); ???? // really necessary? } // Case 2 else { var new_pathname = "/var/www/html" + pathname; ???? } } function proceed_with_resolved_pathname (req, res, pathname) { ???? // send the pathname to the client }
if (pathname.endsWith("/")) { pathname = pathname + "/index.html"; ... }
var url = require('url'); function route(request, response) { var pathname = decodeURI(url.parse(request.url).pathname); var tilde = require('tilde-expansion'); var words = pathname.split('/'); // words[0] is '' and words[1] is '~...' because pathname starts with '/'. // Case 1 if (words[1] != undefined && words[1][0] == '~') { // e.g., /~tom/... tilde(words[1], function(expanded) { // Note that a callback function is used. var new_pathname = expanded + '/???'; // 'public_html' should be included. for (var i = 2; i < words.length; i++) new_pathname += '/' + words[i]; proceed_with_resolved_pathname(request, response, new_pathname); }); } // Case 2 else { var new_pathname = "/var/www/html" + pathname; proceed_with_resolved_pathname(request, response, new_pathname); } } function proceed_with_resolved_pathname(req, res, pathname) { // Case 3 ???? // what if pathname ends with '/'? res.writeHead(200, {"Content-Type": "text/html"}); // text/html, not text/plain, in this example res.write("<h1>Hello World!</h1><br>"); res.write(??? + "<br>"); res.end(); }
const path = require("path"); // reference: Node.js Path Module let fileordirname = path.basename(pathname); let words = fileordirname.split("."); if (words.length > 1) { let extension = words[words.length - 1]; ... } else { ... }
const path = require("path"); let fileordirname = path.basename(pathname); let words = fileordirname.split("."); let extension; if (words.length > 1) { extension = words[words.length - 1]; } else { pathname = ???? extension = ???? } ...
var url = require('url'); function route(request, response) { var pathname = decodeURI(url.parse(request.url).pathname); var tilde = require('tilde-expansion'); var words = pathname.split('/'); // words[0] is '' and words[1] is '~...' because pathname starts with '/'. // Case 1 if (words[1] != undefined && words[1][0] == '~') { // e.g., /~tom/... tilde(words[1], function(expanded) { // Note that a callback function is used. var new_pathname = expanded + '/???'; // 'public_html' should be included. for (var i = 2; i < words.length; i++) new_pathname += '/' + words[i]; proceed_with_resolved_pathname(request, response, new_pathname); }); } // Case 2 else { var new_pathname = "/var/www/html" + pathname; proceed_with_resolved_pathname(request, response, new_pathname); } } ???? function proceed_with_resolved_pathname(req, res, pathname) { // Case 3 if (pathname.endsWith("/")) pathname = pathname + "/index.html"; // Case 4 ???? res.writeHead(200, {"Content-Type": "text/html"}); // text/html, not text/plain, in this example res.write("<h1>Hello World!</h1><br>"); res.write(??? + "<br>"); res.write("Extension: " + ??? + "<br>"); res.end(); }
<HTML> <HEAD> <meta HTTP-EQUIV="REFRESH" content="0; url=http://www.tru.ca:80/science/programs/compsci.html"> </HEAD> </HTML>
response.writeHead(301, {'Location': different_location});
var fs = require('fs'); var filename = 'test.html'; fs.readFile(filename, 'utf8', function(err, content) { if (!err) { console.log(content); } else { console.log(err); } });
router.js
.if (extension != 'sjs' && extension != 'php') { var fs = require('fs'); // reference: Node.js File System Module if (extension == 'html' || extension == 'htm') content_type = 'text/html'; else if ... ... fs.readFile(pathname, 'utf8', function(err, content) { if (!err) { response.writeHead(200, {'Content-type': content_type}); // 200: OK; important response.write(content); response.end(); } else { response.writeHead(404, {'Content-type': "text/html"}); // 4xx: client error response.end("<html><body><h1>Not Found</h1><p>The requested URL was not found on this server.</p><hr></body></html>"); } }); }
// A server-side JavaScript file, e.g., echo_server.sjs and calculator_server.sjs: // _GET: object for the GET data // _POST: object for the POST data // callback: callback function to pass a message back to the client function proceed(_GET, _POST, callback) { ... } exports.proceed = proceed;
.sjs
?
if (extension == 'sjs') { if (request.method.toLowerCase() == "get") { ... } else if (request.???? == '???') { ... } ... }
'http://test.com/start.html?command=Login&username=foo&password=topsecret'
.decodeURI(url.parse(request.url).pathname)
→ '/start.html'
decodeURI(url.parse(request.url).query)
→ 'command=Login&username=foor&password=topsecret'
var _GET = querystring.parse(decodeURI(url.parse(request.url).query))
→ { command:'Login', username:'foo', password:'topsecret' }
_GET['command']
→ 'Login'
JSON.stringfy()
request
' is an Event Emitter object, and
it will emit the 'data'
event whenever the incoming POST data is received.
When there is no more incoming POST data, the 'end'
event is emitted..on()
method on 'request
' can used to listen to these events.var query = ''; var _POST = {}; request.on('data', function(chunk) { // request is an Event Emitter. query += chunk; }); request.???('end', function() { // the end of the data if (query != '') _POST = ???? // parsing using the 'querystring' module. Check the example in the above 'GET' case. });
_POST
.
//---- TRUWSJS ----
var sjs = ???(pathname); // 'pathname' is a sjs script file. This file is required as a module. For example, test.sjs.
// We assume that all '.sjs' programs have the function, proceed(),
// that is the starting point like main() in Java and C/C++ programs.
// _GET: object for the GET query; _POST: object for the POST query
// For example, { command:'Login', username:'foo', password:'topsecret' }
sjs.proceed(_GET, _POST, function(content) { // callback function to get the result from the sjs program
....
response.???("" + content);
response.???();
});
//---- test.sjs ----
function proceed(_GET, _POST, callback) {
var content;
if (_GET['command'] == 'Login') // For example
...
....
???(content); // Don't forget that this function should pass a message back through callback
}
???.??? = proceed;
try-catch
?throw
?isNaN()
do?var divide = function(x, y) { if (y === 0) // throw new Error({name: 'Divide', message: "Can't divide by zero"}); // or throw {name: 'Divide', message: "Can't divide by zero"}; else return x/y; }; try { var result = divide(4, 2); ... } ??? (e) { console.log(e.???); // Not just e. e.name, e.stack, e.message, ... }
??? { var sjs = require(pathname); // We assume all '.sjs' programs have proceed(). sjs.proceed(_GET, _POST, function(html_content) { .... }); } ??? (err) { .... }
??? { var sjs = require(pathname); // We assume all '.sjs' programs have proceed(). var ended = false; sjs.proceed(_GET, _POST, function(html_content) { if (!ended) { .... // write(), ..., end() delete require.cache[require.resolve(pathname)]; // in order to unload this .sjs module; // https://nodejs.org/api/modules.html#requirecache ended = true; // when the callback function is invoked multiple times from the sjs app, // response.end() is invoked again. // It causes an error that cannot be caught. } }); } catch (err) { .... ???[???]; // in order to unload this .sjs module }
var https = require('https'); var fs = require('fs'); var options = { key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'), // Key cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem') // Certificate }; https.???(options, function (req, res) { // similar to http res.writeHead(200); res.end("Hello world!\n"); }).???(8443);
var https = require('https'), pem = require('pem'); pem.createCertificate({days:100, selfSigned:true}, function(err, keys) { if (!err) https.???({key: keys.serviceKey, cert: keys.certificate}, function(req, res) { res.writeHead(200); res.end("Hello world!\n") }).???(8443); });
var http = require('http'); var https = require('https'); var pem = require('pem'); //var ws_server = require('./ws_server'); function start(route) { // HTTP server var server = http.???(function(request, response) { route(request, response); }); server.???(8080); // WebSocket server integrated with HTTP server // It will be discussed later. //ws_server.start(server); // WebSocket server: ws Node.js module // HTTPS server pem.createCertificate({days:100, selfSigned:true}, function(err, keys) { if (!err) https.???({key: keys.serviceKey, cert: keys.certificate}, function(request, response) { ???(???, ???); }).???(8443); }); } ???.start = start;